#include "executor.h"
#include "stdio.h"

AlertFunc g_alertFuncFork = NULL;

typedef enum {
    // CLEAN
    GOT_CLEAN,
    NOT_CLEAN,

    // ALERT
    GOT_ALERT,
    NOT_ALERT,
} OUTER_TYPE;

typedef struct _alertPos {
    int        x, y;
    OUTER_TYPE haveAlert;
} AlertPos;

typedef struct _cleanPos {
    int        x, y;
    OUTER_TYPE haveClean;
} CleanPos;

void RegAlertFunc(AlertFunc fn)
{
    // static AlertFunc g_alertFunc = fn;
    g_alertFuncFork = fn;
}

void SetCleanPos(Executor *e, Postion p)
{
    e->cleanPos.x = p.x;
    e->cleanPos.y = p.y;
}

CleanFunc g_cleanFuncFork = NULL;

void RegCleanFunc(CleanFunc fn) { g_cleanFuncFork = fn; }

void ExecutorClean(Executor *e)
{
    if (e->p.x == e->cleanPos.x && e->p.y == e->cleanPos.y) {
        if (g_cleanFuncFork == NULL) {
            printf("not reg alert func\n");
            return;
        }
        if (e->haveClean == GOT_CLEAN) {
            printf("have got clean\n");
            return;
        }
        e->haveClean = GOT_CLEAN;
        g_cleanFuncFork(e->cleanPos.x, e->cleanPos.y);
    }
}

// singleton pattern
// recommand static not global var
Executor *executor_create()
{
    static Executor e = {0};
    return &e;
}

void ExecutorInit(Executor *e)
{
    e->heading = NORTH;
    e->p.x     = 0;
    e->p.y     = 0;
}

void ExecutorAlert(Executor *e)
{
    if (e->p.x == e->alertPos.x && e->p.y == e->alertPos.y) {
        if (g_alertFuncFork == NULL) {
            printf("not reg alert func\n");
            return;
        }
        g_alertFuncFork(ALERT_EMEGE, e->alertPos.x, e->alertPos.y);
    }
}

Postion executor_get_pos(const Executor *e) { return e->p; }

void Forward(Executor *e)
{
    switch (e->heading) {
    case NORTH:
        e->p.y++;
        break;
    case SOUTH:
        e->p.y--;
        break;
    case EAST:
        e->p.x++;
        break;
    case WEST:
        e->p.x--;
        break;
    default:
        printf("do not know the direction\n");
        break;
    }
    ExecutorAlert(e);
    ExecutorClean(e);
};

void Backward(Executor *e)
{
    switch (e->heading) {
    case NORTH:
        e->p.y--;
        break;
    case SOUTH:
        e->p.y++;
        break;
    case EAST:
        e->p.x--;
        break;
    case WEST:
        e->p.x++;
        break;
    default:
        printf("backward do not know the direction\n");
        break;
    }
    ExecutorAlert(e);
    ExecutorClean(e);
};

void TurnRound(Executor *e)
{
    switch (e->heading) {
    case NORTH:
        e->heading = SOUTH;
        break;
    case SOUTH:
        e->heading = NORTH;
        break;
    case EAST:
        e->heading = WEST;
        break;
    case WEST:
        e->heading = EAST;
        break;
    default:
        printf("TurnRound do not know the direction\n");
        break;
    }

    ExecutorAlert(e);
    ExecutorClean(e);
};

void SetAlertPos(Executor *e, Postion p)
{
    e->alertPos.x = p.x;
    e->alertPos.y = p.y;
}
